package cloud.xlh.infrastructure.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.FatalBeanException;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.net.UnknownHostException;

import static org.springframework.beans.BeanUtils.getPropertyDescriptors;

/**
 * Created with IntelliJ IDEA.
 *
 * @ project name : xlh_osms
 * @ Author: XuLeHuang
 * @ Date: 2023/1/9 19:20
 * @ Description:
 */
@Slf4j
public class CommonUtil {
    /**
     * 源码版忽略大小写反射浅拷贝
     */
    public static void copyPropertiesIgnoreCase(Object sourceObject, Object targetObject) {
        Assert.notNull(sourceObject, "Source must not be null");
        Assert.notNull(targetObject, "Target must not be null");
        Class<?> actualEditable = targetObject.getClass();
        Class<?> sourceObjectClass = sourceObject.getClass();
        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
        PropertyDescriptor[] sourcePds = getPropertyDescriptors(sourceObjectClass);
        PropertyDescriptor[] var7 = targetPds;
        PropertyDescriptor[] var10 = sourcePds;
        int var8 = targetPds.length;
        int var11 = sourcePds.length;
        for (int var9 = 0; var9 < var8; ++var9) {
            PropertyDescriptor targetPd = var7[var9];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null) {
                for (int var12 = 0; var12 < var11; ++var12) {
                    PropertyDescriptor sourcePd = var10[var12];
                    if (targetPd.getName().equalsIgnoreCase(sourcePd.getName())) {
                        if (sourcePd != null) {
                            Method readMethod = sourcePd.getReadMethod();
                            if (readMethod != null) {
                                ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
                                ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
                                boolean isAssignable = !sourceResolvableType.hasUnresolvableGenerics() && !targetResolvableType.hasUnresolvableGenerics() ? targetResolvableType.isAssignableFrom(sourceResolvableType) : ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType());
                                if (isAssignable) {
                                    try {
                                        if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                            readMethod.setAccessible(true);
                                        }
                                        Object value = readMethod.invoke(sourceObject);
                                        if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                            writeMethod.setAccessible(true);
                                        }
                                        writeMethod.invoke(targetObject, value);
                                    } catch (Throwable var18) {
                                        throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var18);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取IP地址
     */
    public static String getIpAddress(HttpServletRequest httpServletRequest) {
        String ipAddress = httpServletRequest.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = httpServletRequest.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = httpServletRequest.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = httpServletRequest.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                }
                if (inet.getHostAddress() != null) {
                    ipAddress = inet.getHostAddress();
                }
            }
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

    /**
     * 获取IP地址-网关过滤器专用
     */
    public static String getIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        return ip;
    }

}
